#ifndef __GLF_CORE_PROPERTIES_H_INCLUDED__
#define __GLF_CORE_PROPERTIES_H_INCLUDED__

#include <map>
#include <iosfwd>

namespace glf {

struct RuntimeInfos {
	uint64 taskResidentSize;
	uint64 taskVirtualSize;
	uint64 freeMemory;
	uint64 usedMemory;
	uint64 freeDiskSpace;
	uint64 totalDiskSpace;
};

void GetRuntimeInfos(RuntimeInfos& infos);

class PropertyMap {
public:
	static const char* const PROP_HW_MACHINE;			
	static const char* const PROP_HW_MODEL;			
	static const char* const PROP_HW_NCPU;			
	static const char* const PROP_HW_BYTEORDER;		
	static const char* const PROP_HW_PHYSMEM;			
	static const char* const PROP_HW_USERMEM;		
	static const char* const PROP_HW_PAGESIZE;		
	static const char* const PROP_HW_FLOATINGPOINT;	
	static const char* const PROP_HW_MACHINE_ARCH;	
	
	static const char* const PROP_HW_VECTORUNIT;
	static const char* const PROP_HW_BUS_FREQ;
	static const char* const PROP_HW_CPU_FREQ;
	static const char* const PROP_HW_CACHELINE;
	static const char* const PROP_HW_L1ICACHESIZE;
	static const char* const PROP_HW_L1DCACHESIZE;
	static const char* const PROP_HW_L2SETTINGS;
	static const char* const PROP_HW_L2CACHESIZE;
	static const char* const PROP_HW_L3SETTINGS;
	static const char* const PROP_HW_L3CACHESIZE;
	static const char* const PROP_HW_TB_FREQ;
	static const char* const PROP_HW_MEMSIZE;	
	static const char* const PROP_HW_AVAILCPU;
	static const char* const PROP_HW_MAXID;
	
	static const char* const PROP_SVN_GLF_URL;		
	static const char* const PROP_SVN_GLF_REVISION;	
	
	static const char* const PROP_SVN_GLITCH_URL;		
	static const char* const PROP_SVN_GLITCH_REVISION;

	static const char* const PROP_SVN_VOX_URL;		
	static const char* const PROP_SVN_VOX_REVISION;	

	static const char* const PROP_SVN_SWF_URL;		
	static const char* const PROP_SVN_SWF_REVISION;	

	enum ValueType {
		EVT_ANY = 0,
		EVT_INT32,
		EVT_INT64,
		EVT_FLOAT,
		EVT_BOOL,
		EVT_STRING,
		EVT_COUNT,
	};
	enum EFlag {
		EF_NONE						= 0x00,
		EF_PERSISTANT				= 0x01,
		EF_LR_QUERY_FIRST			= 0x02,	//LR = launchreporter
		EF_LR_QUERY_FULL			= 0x04,
		EF_LR_QUERY_SUSPENDRESUME	= 0x08,
		
		EF_LR_ALWAYS				= EF_LR_QUERY_FIRST|EF_LR_QUERY_FULL|EF_LR_QUERY_SUSPENDRESUME,
	};

	static const char* GetTypeName(ValueType vt);
	static ValueType GetTypeFromName(const char*);

	typedef int int32;

	struct Value {

		Value() 
			: flags(EF_NONE)
			, type(EVT_COUNT) 
		{}
		explicit Value(int32 value, int flags=EF_NONE) 
			: flags(flags)
			, type(EVT_INT32) 
		{ valueInt32 = value; }
		explicit Value(int64 value, int flags=EF_NONE) 
			: flags(flags)
			, type(EVT_INT64) 
		{ valueInt64 = value; }
		explicit Value(bool value, int flags=EF_NONE) 
			: flags(flags)
			, type(EVT_BOOL) 
		{ valueBool = value; }
		explicit Value(float value, int flags=EF_NONE) 
			: flags(flags)
			, type(EVT_FLOAT) 
		{	valueFloat = value; }
		explicit Value(const char* value, int flags=EF_NONE) 
			: flags(flags)
			, type(EVT_STRING) 
		{ valueString = value; }
		explicit Value(const std::string& value, int flags=EF_NONE) 
			: flags(flags)
			, type(EVT_STRING) 
		{ valueString = value; }
		
		int flags;
		ValueType type;
		union {
			int32 valueInt32;
			int64 valueInt64;
			float valueFloat;
			bool valueBool;
		};
		std::string valueString;
		
		std::string getAsString(bool withType=false) const;
		const char* GetTypeName() const {
			return PropertyMap::GetTypeName(type);
		}

		bool IsPersistant() const {
			return (flags & EF_PERSISTANT) != 0;
		}

		void SetFlag(int flag, bool value=true) {
			if(value)
				flags |= flag;
			else
				flags &= ~flag;
		}

		static Value FromString(const char* type, const char* value);
	};

	typedef std::string key_t;
	typedef Value value_t;
	typedef std::map<key_t, Value> map_t;

	static PropertyMap& Instance() {
		return *sThis;
	}
	
	void SetProperty(const key_t& key, const std::string& value, int flags=EF_NONE);
	void SetProperty(const key_t& key, const char* value, int flags=EF_NONE);

	template<typename T>
	void SetPropertyT(const key_t& key, const T& value, int flags=EF_NONE) {
		Value v(value);
		SetProperty(key, v, flags);
	}

	const map_t& GetProperties() const;

	bool HasProperty(const key_t& key) const;
	void SetPersistant(const key_t& key);
	void SetFlag(const key_t& key, int flags);

	const std::string& GetProperty(const key_t& key) const;
	
	struct Result {
		enum E {
			OK,
			WRONG_TYPE,
			MISSING,
		};
		E status;
		Value value;
		
		operator bool() {
			return status == OK;
		}
	};
	
	Result GetPropertyEx(const key_t& key, ValueType vt=EVT_ANY) const;

	Result GetPropertyInt32(const key_t& key) const {
		return GetPropertyEx(key, EVT_INT32);
	}
	Result GetPropertyInt64(const key_t& key) const {
		return GetPropertyEx(key, EVT_INT64);
	}
	Result GetPropertyBool(const key_t& key) const {
		return GetPropertyEx(key, EVT_BOOL);
	}
	Result GetPropertyFloat(const key_t& key) const {
		return GetPropertyEx(key, EVT_FLOAT);
	}
	Result GetPropertyString(const key_t& key) const {
		return GetPropertyEx(key, EVT_STRING);
	}

	int32 GetPropertyInt32(const key_t& key, int32 defaultValue) const {
		Result r = GetPropertyEx(key, EVT_INT32);
		return r ? r.value.valueInt32 : defaultValue;
	}
	int64 GetPropertyInt64(const key_t& key, int64 defaultValue) const {
		Result r = GetPropertyEx(key, EVT_INT64);
		return r ? r.value.valueInt64 : defaultValue;
	}
	bool GetPropertyBool(const key_t& key, bool defaultValue) const {
		Result r = GetPropertyEx(key, EVT_BOOL);
		return r ? r.value.valueBool : defaultValue;
	}
	std::string GetPropertyString(const key_t& key, const std::string& defaultValue) const {
		Result r = GetPropertyEx(key, EVT_STRING);
		return r ? r.value.valueString : defaultValue;
	}

	void PrintAll() const;

	void EnableLogging(bool value = true) {
		mIsLogging = true;
	}
	bool IsLogging() const {
		return mIsLogging;
	}

	void LoadLastPersistant();

private:
	void SetProperty(const key_t& key, Value& v, int flags = EF_NONE);

	void SavePersistant();
	

	friend struct GlobalsBase;
	PropertyMap();

	void SetDefaultProperties();
	
	static PropertyMap* sThis;

	std::string mEmpty;
	map_t mMap;

	bool mIsLogging;
	bool mLastLogHasBeenLoaded;
};
}

std::ostream& operator<<(std::ostream& os, const glf::PropertyMap::Value& v);


#endif